package com.keywaysoft.workflow.service.impl;

import com.keywaysoft.workflow.service.IProcessImage;
import com.keywaysoft.workflow.utils.R;
import com.keywaysoft.workflow.utils.exception.BizException;
import com.keywaysoft.workflow.vo.VariableInstanceVO;
import lombok.extern.slf4j.Slf4j;
import org.activiti.bpmn.model.Process;
import org.activiti.bpmn.model.*;
import org.activiti.engine.HistoryService;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.history.*;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;

/**
 * @author zhaojx
 */
@Slf4j
@Service
public class IProcessImageImpl implements IProcessImage {

    @Resource
    private RepositoryService repositoryService;
    @Resource
    private HistoryService historyService;

    @Override
    public R<List<HistoricTaskInstance>> InstancesByUser(String userkey,String key) {
        try {
            HistoricTaskInstanceQuery historicTaskInstanceQuery = historyService.createHistoricTaskInstanceQuery();
            historicTaskInstanceQuery.orderByHistoricTaskInstanceEndTime().finished().asc()
                    .taskAssignee(userkey);
            if(StringUtils.isNotBlank(key)){
                historicTaskInstanceQuery.processDefinitionKey(key);
            }
            List<HistoricTaskInstance> historicTaskInstances =historicTaskInstanceQuery.list();
            return R.success(historicTaskInstances);
        } catch (Exception e) {
            return R.fail("获取历史任务失败", e.toString());
        }

    }

    @Override
    public R<List<HistoricTaskInstance>> getInstancesByPiID(String piID) {
        try {
            List<HistoricTaskInstance> historicTaskInstances = historyService.createHistoricTaskInstanceQuery()
                    .orderByHistoricTaskInstanceStartTime().desc()
                    .processInstanceId(piID)
                    .list();
            return R.success(historicTaskInstances);
        } catch (Exception e) {
            return R.fail("获取历史任务失败", e.toString());
        }
    }


    @Override
    public R<List<HistoricProcessInstance>> myProcessStarted(String userKey) {
        return R.success(historyService.createHistoricProcessInstanceQuery().startedBy(userKey).list());
    }

    @Override
    public R<Map<String, Object>> gethighLine(String instanceId, String userkey) {
        try {
            HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery()
                    .processInstanceId(instanceId).singleResult();
            //获取bpmnModel对象
            BpmnModel bpmnModel = repositoryService.getBpmnModel(historicProcessInstance.getProcessDefinitionId());
            //因为我们这里只定义了一个Process 所以获取集合中的第一个即可
            Process process = bpmnModel.getProcesses().get(0);
            //获取所有的FlowElement信息
            Collection<FlowElement> flowElements = process.getFlowElements();

            Map<String, String> map = new HashMap<>();
            for (FlowElement flowElement : flowElements) {
                //判断是否是连线
                if (flowElement instanceof SequenceFlow) {
                    SequenceFlow sequenceFlow = (SequenceFlow) flowElement;
                    String ref = sequenceFlow.getSourceRef();
                    String targetRef = sequenceFlow.getTargetRef();
                    map.put(ref + targetRef, sequenceFlow.getId());
                }
            }

            //获取流程实例 历史节点(全部)
            List<HistoricActivityInstance> list = historyService.createHistoricActivityInstanceQuery()
                    .processInstanceId(instanceId)
                    .list();
            //各个历史节点   两两组合 key
            Set<String> keyList = new HashSet<>();
            for (HistoricActivityInstance i : list) {
                for (HistoricActivityInstance j : list) {
                    if (i != j) {
                        keyList.add(i.getActivityId() + j.getActivityId());
                    }
                }
            }
            //高亮连线ID
            Set<String> highLine = new HashSet<>();
            keyList.forEach(s -> highLine.add(map.get(s)));


            //获取流程实例 历史节点（已完成）
            List<HistoricActivityInstance> listFinished = historyService.createHistoricActivityInstanceQuery()
                    .processInstanceId(instanceId)
                    .finished()
                    .list();
            //高亮节点ID
            Set<String> highPoint = new HashSet<>();
            listFinished.forEach(s -> highPoint.add(s.getActivityId()));

            //获取流程实例 历史节点（待办节点）
            List<HistoricActivityInstance> listUnFinished = historyService.createHistoricActivityInstanceQuery()
                    .processInstanceId(instanceId)
                    .unfinished()
                    .list();

            //需要移除的高亮连线
            Set<String> set = new HashSet<>();
            //待办高亮节点
            Set<String> waitingToDo = new HashSet<>();
            listUnFinished.forEach(s -> {
                waitingToDo.add(s.getActivityId());

                for (FlowElement flowElement : flowElements) {
                    //判断是否是 用户节点
                    if (flowElement instanceof UserTask) {
                        UserTask userTask = (UserTask) flowElement;

                        if (userTask.getId().equals(s.getActivityId())) {
                            List<SequenceFlow> outgoingFlows = userTask.getOutgoingFlows();
                            //因为 高亮连线查询的是所有节点  两两组合 把待办 之后  往外发出的连线 也包含进去了  所以要把高亮待办节点 之后 即出的连线去掉
                            if (outgoingFlows != null && outgoingFlows.size() > 0) {
                                outgoingFlows.forEach(a -> {
                                    if (a.getSourceRef().equals(s.getActivityId())) {
                                        set.add(a.getId());
                                    }
                                });
                            }
                        }
                    }
                }
            });

            highLine.removeAll(set);

            //存放 高亮 我的办理节点
            Set<String> iDo = new HashSet<>();
            //当前用户已完成的任务
            List<HistoricTaskInstance> taskInstanceList = historyService.createHistoricTaskInstanceQuery()
                    .taskAssignee(userkey)
                    .finished()
                    .processInstanceId(instanceId).list();

            taskInstanceList.forEach(a -> iDo.add(a.getTaskDefinitionKey()));

            Map<String, Object> reMap = new HashMap<>();
            reMap.put("highPoint", highPoint);
            reMap.put("highLine", highLine);
            reMap.put("waitingToDo", waitingToDo);
            reMap.put("iDo", iDo);

            return R.success(reMap);
        } catch (Exception e) {
            return R.fail("渲染历史流程失败", e.toString());
        }
    }


    /**
     * 功能描述:查询流程历史变量
     */
    @Override
    public R<List<VariableInstanceVO>> historicVariable(String processInstanceId) {
        List<VariableInstanceVO> variableInstanceVOS = new ArrayList<>();
        if (StringUtils.isEmpty(processInstanceId)) {
            return R.fail(new BizException("param error"));
        }
        try {
            List<HistoricVariableInstance> list = historyService.createHistoricVariableInstanceQuery()
                    .processInstanceId(processInstanceId).list();
            if (list != null && list.size() > 0) {
                System.out.println("流程实例ID:" + processInstanceId);
                for (HistoricVariableInstance h : list) {
                    VariableInstanceVO vo = new VariableInstanceVO();
                    vo.setId(h.getId());
                    vo.setProcessInstanceId(h.getProcessInstanceId());
                    vo.setVariableName(h.getVariableName());
                    vo.setValue(h.getValue());
                    vo.setCreateTime(h.getCreateTime());
                    vo.setVariableTypeName(h.getVariableTypeName());
                    vo.setTaskId(h.getTaskId());

                    variableInstanceVOS.add(vo);
                }
            }

        } catch (Exception e) {
            return R.fail(new BizException(e.getMessage()));
        }
        return R.success(variableInstanceVOS);
    }


}
